/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <baja/graphics/dx11.1/details/common.hpp>
#include <baja/graphics/dx11.1/graphics_fwd.hpp>
#include <baja/graphics/dx11.1/details/enum_mappings.hpp>

namespace baja { namespace graphics { namespace dx11_1 {

class material_collection : public imaterial_collection
{
public:
    material_collection() {}

    static std::shared_ptr<material_collection> create(
        const std::vector<std::shared_ptr<imaterial>>& materials,
        const std::vector<std::string>& materialNames
        )
    {
        std::shared_ptr<material_collection> returnValue = std::make_shared<material_collection>();
        returnValue->initialize(materials, materialNames);
        return returnValue;
    }

    // gets count of materials in the collection
    size_t getMaterialCount() 
    {
        return _materials.size();
    }

    // gets material at given index
    std::shared_ptr<imaterial> getMaterial(const size_t index)
    {
        BAJA_CHECK_ARG(index < this->getMaterialCount());
        
        return _materials[index];
    }

    // gets material by name
    std::shared_ptr<imaterial> getMaterialByName(const char* name)
    {
        BAJA_CHECK_ARG(name);

        // find the index where requested material exists
        for(uint32 i = 0; i < this->getMaterialCount(); i++)
        {
            if (_materialNames[i].compare(name) == 0)
            {
                // index found, get the material and return
                return this->getMaterial(i);
            }
        }

        // TEST: test this method
        win32_result((HRESULT)E_POINTER);
        return nullptr;
    }

    // clones this material collection
    std::shared_ptr<imaterial_collection> clone()
    {
        // TEST: this entire method

        // clone the material array
        std::vector<std::shared_ptr<imaterial>> newMaterials;
        std::for_each(
            _materials.begin(),
            _materials.end(),
            [&](const std::shared_ptr<imaterial>& mat)
        {
            std::shared_ptr<imaterial> newMat = mat->clone();
            newMaterials.push_back(newMat);
        });

        std::vector<std::string> newMaterialNames;
        std::for_each(
            _materialNames.begin(),
            _materialNames.end(),
            [&](const std::string& name)
        {
            newMaterialNames.push_back(name); // TEST: is this creating a clone of the string?
        });

        // allocate the clone object
        std::shared_ptr<material_collection> newCollection;
        newCollection = material_collection::create(
            newMaterials,
            newMaterialNames
            );

        return newCollection;
    }

private:
    // initializes the material collection with data
    void initialize(
        const std::vector<std::shared_ptr<imaterial>>& materials,
        const std::vector<std::string>& materialNames
        )
    {
        _materials = std::vector<std::shared_ptr<imaterial>>(materials);
        _materialNames = std::vector<std::string>(materialNames);
    }

    std::vector<std::shared_ptr<imaterial>> _materials;
    std::vector<std::string> _materialNames;
};

}}} // namespace baja.graphics.dx11_1

namespace baja { namespace graphics {

inline std::shared_ptr<imaterial_collection> createMaterialCollection(
    const std::vector<std::shared_ptr<imaterial>>& materials,
    const std::vector<std::string>& materialNames
    )
{
    std::shared_ptr<baja::graphics::dx11_1::material_collection> returnValue = baja::graphics::dx11_1::material_collection::create(
        materials,
        materialNames
        );

    return std::dynamic_pointer_cast<imaterial_collection>(returnValue);
}

}} // namespace baja.graphics